import * as THREE from 'three';
import type { CollisionResult } from './collisionDetector';
import { CarController, type CarState } from './carControls';

// 响应配置接口
export interface ResponseConfig {
  elasticity: number;         // 弹性系数 (0-1)
  friction: number;           // 摩擦系数 (0-1)
  minVelocity: number;        // 最小速度阈值
  maxPenetrationCorrection: number;  // 最大穿透修正距离
  positionCorrectionStrength: number;  // 位置修正强度
  velocityDamping: number;    // 速度阻尼
}

// 碰撞响应结果接口
export interface ResponseResult {
  positionCorrected: boolean;
  velocityAdjusted: boolean;
  finalVelocity: number;
  correctionDistance: number;
}

/**
 * 碰撞响应处理器
 * 处理车辆与建筑物碰撞后的物理响应
 */
export class CollisionResponse {
  private config: ResponseConfig;
  private lastCollisionTime: number = 0;
  private collisionCooldown: number = 100; // 碰撞冷却时间（毫秒）

  constructor(config?: Partial<ResponseConfig>) {
    this.config = {
      elasticity: 0.2,
      friction: 0.8,
      minVelocity: 0.1,
      maxPenetrationCorrection: 2.0,
      positionCorrectionStrength: 0.8,
      velocityDamping: 0.3,
      ...config
    };
  }

  /**
   * 解决碰撞
   * @param carGroup 车辆组对象
   * @param carController 车辆控制器
   * @param collisions 碰撞结果数组
   * @returns 响应结果
   */
  public resolveCollisions(
    carGroup: THREE.Group,
    carController: CarController,
    collisions: CollisionResult[]
  ): ResponseResult {
    if (collisions.length === 0) {
      return {
        positionCorrected: false,
        velocityAdjusted: false,
        finalVelocity: carController.getCarState().speed,
        correctionDistance: 0
      };
    }

    const currentTime = Date.now();
    
    // 碰撞冷却检查
    if (currentTime - this.lastCollisionTime < this.collisionCooldown) {
      return {
        positionCorrected: false,
        velocityAdjusted: false,
        finalVelocity: carController.getCarState().speed,
        correctionDistance: 0
      };
    }

    // 找到最严重的碰撞（穿透深度最大）
    const primaryCollision = this.findPrimaryCollision(collisions);
    
    if (!primaryCollision.normal || !primaryCollision.penetrationDepth) {
      return {
        positionCorrected: false,
        velocityAdjusted: false,
        finalVelocity: carController.getCarState().speed,
        correctionDistance: 0
      };
    }

    // 应用位置修正
    const correctionDistance = this.applyPositionCorrection(carGroup, primaryCollision);
    
    // 应用速度响应
    const velocityAdjusted = this.applyVelocityResponse(carController, primaryCollision);
    
    // 更新最后碰撞时间
    this.lastCollisionTime = currentTime;

    return {
      positionCorrected: correctionDistance > 0,
      velocityAdjusted,
      finalVelocity: carController.getCarState().speed,
      correctionDistance
    };
  }

  /**
   * 找到主要碰撞（穿透深度最大的碰撞）
   * @param collisions 碰撞数组
   * @returns 主要碰撞
   */
  private findPrimaryCollision(collisions: CollisionResult[]): CollisionResult {
    return collisions.reduce((primary, current) => {
      const primaryDepth = primary.penetrationDepth || 0;
      const currentDepth = current.penetrationDepth || 0;
      return currentDepth > primaryDepth ? current : primary;
    });
  }

  /**
   * 应用位置修正
   * @param carGroup 车辆组对象
   * @param collision 碰撞结果
   * @returns 修正距离
   */
  private applyPositionCorrection(carGroup: THREE.Group, collision: CollisionResult): number {
    if (!collision.normal || !collision.penetrationDepth) {
      return 0;
    }

    // 限制最大修正距离
    const correctionDistance = Math.min(
      collision.penetrationDepth * this.config.positionCorrectionStrength,
      this.config.maxPenetrationCorrection
    );

    // 沿着碰撞法向量推出车辆
    const correctionVector = collision.normal.clone().multiplyScalar(correctionDistance);
    carGroup.position.add(correctionVector);

    return correctionDistance;
  }

  /**
   * 应用速度响应
   * @param carController 车辆控制器
   * @param collision 碰撞结果
   * @returns 是否调整了速度
   */
  private applyVelocityResponse(carController: CarController, collision: CollisionResult): boolean {
    if (!collision.normal) {
      return false;
    }

    const carState = carController.getCarState();
    const currentSpeed = carState.speed;

    // 如果速度太小，直接停止
    if (Math.abs(currentSpeed) < this.config.minVelocity) {
      this.setCarSpeed(carController, 0);
      return true;
    }

    // 计算车辆运动方向
    const moveDirection = new THREE.Vector3(
      Math.sin(carState.rotation),
      0,
      Math.cos(carState.rotation)
    );

    // 计算速度向量在碰撞法向量上的投影
    const velocityMagnitude = Math.abs(currentSpeed);
    const velocityDirection = moveDirection.clone().multiplyScalar(Math.sign(currentSpeed));
    const normalProjection = velocityDirection.dot(collision.normal);

    // 只有当车辆朝向碰撞面时才应用响应
    if (normalProjection <= 0) {
      return false;
    }

    // 计算反射速度
    const reflectedVelocity = velocityDirection.clone().sub(
      collision.normal.clone().multiplyScalar(2 * normalProjection)
    );

    // 应用弹性和摩擦
    const finalSpeed = velocityMagnitude * this.config.elasticity * (1 - this.config.friction);
    
    // 应用阻尼
    const dampedSpeed = finalSpeed * (1 - this.config.velocityDamping);

    // 计算新的速度方向（世界坐标系）
    const newDirection = reflectedVelocity.normalize();
    
    // 将世界坐标系方向转换为车辆局部旋转
    const worldToLocal = Math.atan2(newDirection.x, newDirection.z);
    const newRotation = worldToLocal;
    
    // 更新车辆状态
    this.setCarRotation(carController, newRotation);
    this.setCarSpeed(carController, dampedSpeed);

    return true;
  }

  /**
   * 设置车辆速度（直接修改内部状态）
   * @param carController 车辆控制器
   * @param speed 新速度
   */
  private setCarSpeed(carController: CarController, speed: number): void {
    // 直接修改车辆状态（这是临时方案，理想情况下应该通过CarController的方法）
    const carState = carController.getCarState();
    (carState as any).speed = speed;
  }

  /**
   * 设置车辆旋转（直接修改内部状态）
   * @param carController 车辆控制器
   * @param rotation 新旋转角度
   */
  private setCarRotation(carController: CarController, rotation: number): void {
    // 直接修改车辆状态（这是临时方案，理想情况下应该通过CarController的方法）
    const carState = carController.getCarState();
    (carState as any).rotation = rotation;
  }

  /**
   * 更新配置
   * @param newConfig 新配置
   */
  public updateConfig(newConfig: Partial<ResponseConfig>): void {
    this.config = { ...this.config, ...newConfig };
  }

  /**
   * 获取当前配置
   * @returns 当前配置
   */
  public getConfig(): ResponseConfig {
    return { ...this.config };
  }

  /**
   * 检查是否在碰撞冷却期内
   * @returns 是否在冷却期
   */
  public isInCooldown(): boolean {
    return Date.now() - this.lastCollisionTime < this.collisionCooldown;
  }

  /**
   * 重置碰撞状态
   */
  public reset(): void {
    this.lastCollisionTime = 0;
  }

  /**
   * 设置碰撞冷却时间
   * @param cooldown 冷却时间（毫秒）
   */
  public setCooldown(cooldown: number): void {
    this.collisionCooldown = cooldown;
  }
}